﻿#include "writera661.h"

writera661::writera661()
{

}

void writera661::genEtpFile(QString genEtpPath, EtpXmlData &etpXmlData)
{
    QFileInfo etpInfo(genEtpPath);
    QString tablePath = etpInfo.absolutePath() + "/table.xml";
    QFileInfo tableInfo(tablePath);

    // 如果目录不存在，则尝试创建目录
    QDir dir = etpInfo.dir();
    if (!dir.exists()) {
        if (!dir.mkpath(".")) {
            qDebug() << "无法创建目录：" << dir.absolutePath();
            return;
        }
    }
    QDir table_dir = tableInfo.dir();
    if (!table_dir.exists()) {
        if (!table_dir.mkpath(".")) {
            qDebug() << "无法创建目录：" << table_dir.absolutePath();
            return;
        }
    }

    QFile file(genEtpPath);
    QFile table_file(tablePath);
    QString pdt = "";
    QString sdt = "";

    // 尝试以写入模式打开文件
    if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
    {
        QXmlStreamWriter writer(&file);
        writer.setAutoFormatting(true);

        // 写入XML声明
        writer.writeStartDocument("1.0");

        // 开始Project元素
        writer.writeStartElement("Project");
        writer.writeAttribute("id", etpXmlData.id);
        writer.writeAttribute("oid_count", etpXmlData.oidCount);
        writer.writeAttribute("type", "1");
        //writer.writeAttribute("defaultConfiguration", etpXmlData.defaultConfig);

        /*========== 1. props ===========*/
        writer.writeStartElement("props");

        // 写入etpProps中的属性
        for (const EtpProp &prop : etpXmlData.etpProps.propList) {
            writer.writeStartElement("Prop");
            writer.writeAttribute("id", prop.id);
            writer.writeAttribute("name", prop.name);

            if (!prop.value.isEmpty()) {
                writer.writeTextElement("value", prop.value);
            }

            if (!prop.configuration.isEmpty()) {
                writer.writeTextElement("configuration", prop.configuration);
            }

            writer.writeEndElement(); // Prop
        }

        writer.writeEndElement(); // props

        /*========== 2. roots ===========*/
        writer.writeStartElement("roots");

        // 写入每个Folder
        for (const Folder &folder : etpXmlData.etpRoots.folderList) {

            if(folder.name == "A661 Configuration Files" || folder.name == "Symbol Model Files")
                continue;

            writer.writeStartElement("Folder");
            writer.writeAttribute("id", folder.id);

            // 写入extensions属性
            if (folder.name == "Resource Files") {
                writer.writeAttribute("extensions", "sct;sft;sst;swt");
            } else if (folder.name == "A661 Configuration Files") {
                writer.writeAttribute("extensions", "xml");
            } else if (folder.name == "A661 Resource Files") {
                writer.writeAttribute("extensions", "cnt;pdt;sdt;slc;sld");
            } else if (folder.name == "Symbol Model Files") {
                writer.writeAttribute("extensions", "sdfx");
            } else if (folder.name == "Model Files") {
                writer.writeAttribute("extensions", "rdmf;rdrf;pgfx;asfx;trace");
            }
            writer.writeAttribute("name", folder.name);

            // 写入elements
            writer.writeStartElement("elements");

            // 写入每个FileRef
            for (int i = 0; i < folder.elements.fileRefList.size(); i++) {
                writer.writeStartElement("FileRef");
                writer.writeAttribute("id", folder.elements.fileRefList.at(i).id);

                if(folder.name == "Model Files" && folder.elements.fileRefList.at(i).persist.endsWith("sgfx")){
                    QFileInfo rtp(etpXmlData.rdmfPath.at(i));
                    QString fillRTP = "./" +rtp.fileName();
                    writer.writeAttribute("persistAs", fillRTP);
                    int propNum = folder.elements.fileRefList.at(i).fileProps.propList.size();
                    if(propNum > 0){
                        writer.writeStartElement("props");
                        for(int j = 0; j < propNum; j++){
                            writer.writeStartElement("Prop");
                            writer.writeAttribute("id", folder.elements.fileRefList.at(i).fileProps.propList.at(j).id);
                            writer.writeAttribute("name", folder.elements.fileRefList.at(i).fileProps.propList.at(j).name);
                            writer.writeStartElement("value");
                            writer.writeCharacters(folder.elements.fileRefList.at(i).fileProps.propList.at(j).value);
                            if (folder.elements.fileRefList.at(i).fileProps.propList.at(j).value.startsWith("symbol")) {
                                sdt = folder.elements.fileRefList.at(i).fileProps.propList.at(j).value;
                            }
                            else if(folder.elements.fileRefList.at(i).fileProps.propList.at(j).value.startsWith("picture")){
                                pdt = folder.elements.fileRefList.at(i).fileProps.propList.at(j).value;
                            }
                            writer.writeEndElement();
                            writer.writeEndElement();
                        }
                        writer.writeEndElement();
                    }
                }
                else{
                    QString normalizedPath = folder.elements.fileRefList.at(i).persist;
                    normalizedPath = normalizedPath.replace('\\', '/');
                    if (!normalizedPath.startsWith('$') && !normalizedPath.startsWith("./")) {
                        normalizedPath.prepend("./");
                    }
                    writer.writeAttribute("persistAs", normalizedPath);
                }

                writer.writeEndElement(); // FileRef
            }

            writer.writeEndElement(); // elements
            writer.writeEndElement(); // Folder
        }

        writer.writeEndElement(); // roots

        /*========== 3. configurations ===========*/
        writer.writeStartElement("configurations");

        // 写入每个Configuration
        for (const Configuration &config : etpXmlData.configs.configList) {
            writer.writeStartElement("Configuration");
            writer.writeAttribute("id", config.id);
            writer.writeAttribute("name", config.name);
            writer.writeEndElement(); // Configuration
        }

        writer.writeEndElement(); // configurations

        // 结束Project元素
        writer.writeEndElement(); // Project

        writer.writeEndDocument();
        file.close();
    }
    else
    {
        // 文件打开失败，输出错误信息
        qDebug() << "无法打开文件：" << file.fileName() << " 错误:" << file.errorString();
    }

    if (table_file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
    {
        QXmlStreamWriter writer(&table_file);
        writer.setAutoFormatting(true);

        // 开始写入XML文档
        writer.writeStartDocument();

        writer.writeStartElement("table");

        // 写入第一行记录
        writer.writeStartElement("picture_table");
        writer.writeCharacters(pdt);
        writer.writeEndElement();

        // 写入第二行记录
        writer.writeStartElement("symbol_table");
        writer.writeCharacters(sdt);
        writer.writeEndElement();

        writer.writeEndElement();

        // 结束文档
        writer.writeEndDocument();
        table_file.close();
    }
    else
    {
        // 文件打开失败，输出错误信息
        qDebug() << "无法打开文件：" << table_file.fileName() << " 错误:" << table_file.errorString();
    }
}


//null ide
void writera661::printRdmfNullIDE(QXmlStreamWriter &writer)
{
    //IDE
    writer.writeStartElement("IDE");
    //ide end
    writer.writeEndElement();
}

//ide
void writera661::printRdmfIDE(QXmlStreamWriter &writer, const QString &rdmfPath, const IDE& ide)
{
    writer.writeStartElement("IDE");

    if(!ide.project.path.isEmpty())
    {
        /*========project========*/
        writer.writeStartElement("project");
        QFileInfo fileinfo(rdmfPath);
        writer.writeAttribute("path", fileinfo.path());
        writer.writeEndElement();

        /*========ratio========*/
        writer.writeStartElement("ratio");
        writer.writeAttribute("horizontal", "1");
        writer.writeAttribute("vertical", "1");
        writer.writeEndElement();
    }

    writer.writeEndElement();
}

//symbology
void writera661::printRdmfSymbology(QXmlStreamWriter &writer, const Symbology& symbology)
{
    writer.writeStartElement("symbology");

    /*========colorMode========*/
    writer.writeStartElement("colorMode");
    writer.writeAttribute("value", "RGBA");
    writer.writeEndElement();

    /*========dimension========*/
    writer.writeStartElement("dimension");
    writer.writeAttribute("height", symbology.demension.height);
    writer.writeAttribute("width", symbology.demension.width);
    writer.writeEndElement();

    writer.writeEndElement();
}

//a661
void writera661::printRdmfA661(QXmlStreamWriter &writer, const A661& a661)
{
    writer.writeStartElement("A661");
    writer.writeAttribute("library_version", "1");
    writer.writeAttribute("supp_version", "5");

    /*========a661 prop========*/
    writer.writeStartElement("intprop");
    writer.writeAttribute("name", "ApplicationId");
    writer.writeCharacters(a661.applicationId.value);
    writer.writeEndElement();

    writer.writeEndElement();
}

//dllProp
void writera661::printDllProperties(QXmlStreamWriter &writer, const QString& layerId, const DllProperties& dllProperties, QString oid, const Symbology& symbology
                                    , int inContainer, int layerWidth, int layerHeight, const Rule rule, const Rules rules
                                    , const ExtensionRules eRules, const PropTypes &propTypes, const QMap<QString, QString> &constMap
                                    , const CommuParams &commuParams, const SdyContent &sdys, const int cX, const int cY)
{
    /*------------ 1 判断widget --------------------*/

    int oX = dllProperties.posX.toFloat();
    int oY = dllProperties.posY.toFloat();
    oX = oX / 20;
    oY = oY / 20;
    int maskX = oX;
    int maskY = oY;
    if(inContainer == 0){
        oX = oX - layerWidth / 2;
        oY = oY - layerHeight / 2;
    }
    oX += cX;
    oY += cY;
    int wHeight = dllProperties.height.value.toFloat();
    int wWidth = dllProperties.width.value.toFloat();


    if(rule.hasChildren){
        printWidgetContainer(writer, layerId, dllProperties, oid, oX, oY, wWidth, wHeight, layerWidth, layerHeight, rule, eRules, propTypes
                             , 1, constMap, commuParams, sdys);

        //children
        //writer.writeStartElement("children");            //16
        if (dllProperties.groupChildren) {
            writer.writeStartElement("children");
            inContainer = 1;
            if(dllProperties.name == "MaskContainer"){
                oX = oX - maskX;
                oY = oY - maskY;
            }
            printRdmfLayerWidgetChildren(writer, layerId, *dllProperties.groupChildren, symbology, inContainer, layerWidth, layerHeight, rules, eRules
                                         , propTypes, constMap, commuParams, sdys, oX, oY);
            writer.writeEndElement();
        }
        //group->children end
        //writer.writeEndElement();
    }else{
        printWidgetContainer(writer, layerId, dllProperties, oid, oX, oY, wHeight, wWidth, layerWidth, layerHeight, rule, eRules, propTypes
                             , inContainer, constMap, commuParams, sdys);
    }
}

//LayerWidgetChildren
void writera661::printRdmfLayerWidgetChildren(QXmlStreamWriter &writer, const QString& layerId, const WidgetChildren& widgetChildren, const Symbology& symbology
                                              , int inContainer, int layerWidth, int layerHeight, const Rules rules, const ExtensionRules eRules
                                              , const PropTypes &propTypes, const QMap<QString, QString> &constMap, const CommuParams &commuParams
                                              , const SdyContent &sdys, const int cX, const int cY)
{
    //    qDebug() << "Widgets size:" << widgetChildren.widgets;
    if(widgetChildren.widgets.isEmpty()){

    }
    else{
        QList<WidgetContainer> widgets = widgetChildren.widgets;


        /*_____________逐个输出widget_____________________*/
        for(int i = 0; i < widgets.count(); i++)
        {

            /*========a661 layer widget========*/
            WidgetContainer widget = widgets.at(i);
            DllProperties dllProperties = widget.dllProperties;
            QString oid = widget.oid;

            auto it = std::find_if(rules.rules.begin(),rules.rules.end(),
                                   [&widget](const Rule& rule) {
                                       return rule.name == widget.dllProperties.type;
                                   });

            // 如果找到匹配的 rule，进入 if 分支并使用它
            if (it != rules.rules.end()) {
                const Rule& matchedRule = *it;  // 获取匹配的 rule 的引用

                //widgetContainer
                writer.writeStartElement("widgetContainer");
                writer.writeAttribute("oid", "{"+widget.oid+"}");

                //pathFromRoot
                for(int j = 0; j < widget.dllProperties.inputParameters.paramers.count(); j++)
                {
                    Parameter para = widget.dllProperties.inputParameters.paramers.at(j);
                    if(para.name == "WidgetIdent"){
                        writer.writeStartElement("pathFromRoot");
                        writer.writeAttribute("value", para.initValue);
                        writer.writeEndElement();
                        break;
                    }
                }

                printDllProperties(writer, layerId, dllProperties, oid, symbology, inContainer, layerWidth, layerHeight, matchedRule, rules, eRules
                                   , propTypes, constMap, commuParams, sdys, cX, cY);

            }

            //widgetContainer end
            writer.writeEndElement();



            /*============more widgets====================*/


        }
    }

}

//Layer
void writera661::printRdmfLayer(QXmlStreamWriter &writer, const Layer& layer, const Symbology& symbology, const Rules rules
                                , const ExtensionRules eRules, const PropTypes &propTypes, const QMap<QString, QString> &constMap
                                , const CommuParams &commuParams, const SdyContent &sdys)
{
    /*========a661 layer========*/

    writer.writeStartElement("layer");
    writer.writeAttribute("oid", layer.oid);

    /*========a661 layer pathFromRoot========*/
    writer.writeStartElement("pathFromRoot");
    writer.writeAttribute("value", layer.pathFormRoot.value);
    writer.writeEndElement();

    /*========a661 layer declaration========*/
    writer.writeStartElement("declaration");
    writer.writeEndElement();

    /*========a661 layer properties========*/

    writer.writeStartElement("properties");
    writer.writeAttribute("name", layer.layerProperties.name);
    writer.writeAttribute("unEscapeName", layer.layerProperties.name);

    /*---------visible--------*/
    writer.writeStartElement("visible");
    writer.writeStartElement("init");
    writer.writeCharacters("true");
    writer.writeEndElement();
    writer.writeEndElement();

    /*----------origin--------*/
    writer.writeStartElement("origin");
    writer.writeStartElement("x");
    writer.writeStartElement("init");
    writer.writeCharacters("0");
    writer.writeEndElement();
    writer.writeEndElement();
    writer.writeStartElement("y");
    writer.writeStartElement("init");
    writer.writeCharacters("0");
    writer.writeEndElement();
    writer.writeEndElement();
    writer.writeEndElement();

    /*------------id----------*/
    writer.writeStartElement("id");
    writer.writeStartElement("init");
    writer.writeCharacters(layer.pathFormRoot.value);
    writer.writeEndElement();
    writer.writeEndElement();
    /*----------ratio---------*/
    writer.writeStartElement("ratio");
    writer.writeAttribute("horizontal", "1");
    writer.writeAttribute("vertical", "1");
    writer.writeEndElement();

    writer.writeEndElement();

    /*========a661 layer notifys========*/
    writer.writeStartElement("notifys");

    writer.writeStartElement("notify");
    writer.writeAttribute("id", "10001");
    writer.writeAttribute("name", "ContextNumber");
    writer.writeAttribute("type", "ushort");
    writer.writeAttribute("tag", "A661_SERVER_CONTEXT_NUMBER");
    writer.writeAttribute("parameter", "A661_SERVER_CONTEXT_NUMBER");
    for(const MappingItem& item : sdys.inputItems){
        if(layer.pathFormRoot.value == item.eventVar.layerId && item.eventVar.widgetId == "-1"
            && item.eventVar.paramId == "A661_SERVER_CONTEXT_NUMBER" && item.eventVar.name == "ContextNumber"){
            writer.writeStartElement("control_var");
            writer.writeAttribute("name", item.conVar.name);
            QString type = item.conVar.type;
            if(type == "int16"){
                type = "short";
            }
            else if(type == "uint16"){
                type = "ushort";
            }
            else if(type == "int32"){
                type = "int";
            }
            else if(type == "uint32"){
                type = "uint";
            }
            else if(type == "int64"){
                type = "int64";
            }
            else if(type == "uint64"){
                type = "uint64";
            }
            else if(type == "float32"){
                type = "float";
            }
            else if(type == "float64"){
                type = "real";
            }
            writer.writeAttribute("type", type);
            QString path = item.conVar.instancepath;
            if(path.endsWith('/')){
                path.chop(1);
            }
            writer.writeAttribute("path", path);
            writer.writeAttribute("scope", "inputs");
            writer.writeAttribute("subelement", item.conVar.subelement);
            writer.writeEndElement();
            break;
        }
    }
    writer.writeEndElement();


    writer.writeStartElement("notify");
    writer.writeAttribute("id", "10002");
    writer.writeAttribute("name", "Notify");
    writer.writeAttribute("type", "enum {A661_FALSE, A661_TRUE}");
    writer.writeAttribute("tag", "A661_NOTE_REINIT_LAYER_DATA");
    writer.writeAttribute("parameter", "A661_NOTE_REINIT_LAYER_DATA");
    for(const MappingItem& item : sdys.inputItems){
        if(layer.pathFormRoot.value == item.eventVar.layerId && item.eventVar.widgetId == "-1"
            && item.eventVar.paramId == "A661_NOTE_REINIT_LAYER_DATA" && item.eventVar.name == "Notify"){
            writer.writeStartElement("control_var");
            writer.writeAttribute("name", item.conVar.name);
            QString type = item.conVar.type;
            if(type == "int16"){
                type = "short";
            }
            else if(type == "uint16"){
                type = "ushort";
            }
            else if(type == "int32"){
                type = "int";
            }
            else if(type == "uint32"){
                type = "uint";
            }
            else if(type == "int64"){
                type = "int64";
            }
            else if(type == "uint64"){
                type = "uint64";
            }
            else if(type == "float32"){
                type = "float";
            }
            else if(type == "float64"){
                type = "real";
            }
            writer.writeAttribute("type", type);
            QString path = item.conVar.instancepath;
            if(path.endsWith('/')){
                path.chop(1);
            }
            writer.writeAttribute("path", path);
            writer.writeAttribute("scope", "inputs");
            writer.writeAttribute("subelement", item.conVar.subelement);
            writer.writeEndElement();
            break;
        }
    }
    writer.writeEndElement();


    writer.writeStartElement("notify");
    writer.writeAttribute("id", "10003");
    writer.writeAttribute("name", "Notify");
    writer.writeAttribute("type", "enum {A661_FALSE, A661_TRUE}");
    writer.writeAttribute("tag", "A661_NOTE_LAYER_IS_ACTIVE");
    writer.writeAttribute("parameter", "A661_NOTE_LAYER_IS_ACTIVE");
    for(const MappingItem& item : sdys.inputItems){
        if(layer.pathFormRoot.value == item.eventVar.layerId && item.eventVar.widgetId == "-1"
            && item.eventVar.paramId == "A661_NOTE_LAYER_IS_ACTIVE" && item.eventVar.name == "Notify"){
            writer.writeStartElement("control_var");
            writer.writeAttribute("name", item.conVar.name);
            QString type = item.conVar.type;
            if(type == "int16"){
                type = "short";
            }
            else if(type == "uint16"){
                type = "ushort";
            }
            else if(type == "int32"){
                type = "int";
            }
            else if(type == "uint32"){
                type = "uint";
            }
            else if(type == "int64"){
                type = "int64";
            }
            else if(type == "uint64"){
                type = "uint64";
            }
            else if(type == "float32"){
                type = "float";
            }
            else if(type == "float64"){
                type = "real";
            }
            writer.writeAttribute("type", type);
            QString path = item.conVar.instancepath;
            if(path.endsWith('/')){
                path.chop(1);
            }
            writer.writeAttribute("path", path);
            writer.writeAttribute("scope", "inputs");
            writer.writeAttribute("subelement", item.conVar.subelement);
            writer.writeEndElement();
            break;
        }
    }
    writer.writeEndElement();


    writer.writeStartElement("notify");
    writer.writeAttribute("id", "10004");
    writer.writeAttribute("name", "Notify");
    writer.writeAttribute("type", "enum {A661_FALSE, A661_TRUE}");
    writer.writeAttribute("tag", "A661_NOTE_LAYER_IS_INACTIVE");
    writer.writeAttribute("parameter", "A661_NOTE_LAYER_IS_INACTIVE");
    for(const MappingItem& item : sdys.inputItems){
        if(layer.pathFormRoot.value == item.eventVar.layerId && item.eventVar.widgetId == "-1"
            && item.eventVar.paramId == "A661_NOTE_LAYER_IS_INACTIVE" && item.eventVar.name == "Notify"){
            writer.writeStartElement("control_var");
            writer.writeAttribute("name", item.conVar.name);
            QString type = item.conVar.type;
            if(type == "int16"){
                type = "short";
            }
            else if(type == "uint16"){
                type = "ushort";
            }
            else if(type == "int32"){
                type = "int";
            }
            else if(type == "uint32"){
                type = "uint";
            }
            else if(type == "int64"){
                type = "int64";
            }
            else if(type == "uint64"){
                type = "uint64";
            }
            else if(type == "float32"){
                type = "float";
            }
            else if(type == "float64"){
                type = "real";
            }
            writer.writeAttribute("type", type);
            QString path = item.conVar.instancepath;
            if(path.endsWith('/')){
                path.chop(1);
            }
            writer.writeAttribute("path", path);
            writer.writeAttribute("scope", "inputs");
            writer.writeAttribute("subelement", item.conVar.subelement);
            writer.writeEndElement();
            break;
        }
    }
    writer.writeEndElement();


    writer.writeEndElement();

    /*========a661 layer messages========*/
    writer.writeStartElement("messages");

    writer.writeStartElement("message");
    writer.writeAttribute("id", "20001");
    writer.writeAttribute("name", "ContextNumber");
    writer.writeAttribute("type", "ushort");
    writer.writeAttribute("tag", "A661_UA_CONTEXT_NUMBER");
    writer.writeAttribute("parameter", "A661_UA_CONTEXT_NUMBER");
    for(const MappingItem& item : sdys.outputItems){
        if(layer.pathFormRoot.value == item.eventVar.layerId && item.eventVar.widgetId == "-1"
            && item.eventVar.paramId == "A661_UA_CONTEXT_NUMBER" && item.eventVar.name == "ContextNumber"){
            writer.writeStartElement("control_var");
            writer.writeAttribute("name", item.conVar.name);
            QString type = item.conVar.type;
            if(type == "int16"){
                type = "short";
            }
            else if(type == "uint16"){
                type = "ushort";
            }
            else if(type == "int32"){
                type = "int";
            }
            else if(type == "uint32"){
                type = "uint";
            }
            else if(type == "int64"){
                type = "int64";
            }
            else if(type == "uint64"){
                type = "uint64";
            }
            else if(type == "float32"){
                type = "float";
            }
            else if(type == "float64"){
                type = "real";
            }
            writer.writeAttribute("type", type);
            QString path = item.conVar.instancepath;
            if(path.endsWith('/')){
                path.chop(1);
            }
            writer.writeAttribute("path", path);
            writer.writeAttribute("scope", "outputs");
            writer.writeAttribute("subelement", item.conVar.subelement);
            writer.writeEndElement();
            break;
        }
    }
    writer.writeEndElement();

    writer.writeStartElement("message");
    writer.writeAttribute("id", "20002");
    writer.writeAttribute("name", "Emit");
    writer.writeAttribute("type", "enum {A661_FALSE, A661_TRUE}");
    writer.writeAttribute("tag", "A661_REQ_LAYER_ACTIVE");
    writer.writeAttribute("parameter", "A661_REQ_LAYER_ACTIVE");
    for(const MappingItem& item : sdys.outputItems){
        if(layer.pathFormRoot.value == item.eventVar.layerId && item.eventVar.widgetId == "-1"
            && item.eventVar.paramId == "A661_REQ_LAYER_ACTIVE" && item.eventVar.name == "Emit"){
            writer.writeStartElement("control_var");
            writer.writeAttribute("name", item.conVar.name);
            QString type = item.conVar.type;
            if(type == "int16"){
                type = "short";
            }
            else if(type == "uint16"){
                type = "ushort";
            }
            else if(type == "int32"){
                type = "int";
            }
            else if(type == "uint32"){
                type = "uint";
            }
            else if(type == "int64"){
                type = "int64";
            }
            else if(type == "uint64"){
                type = "uint64";
            }
            else if(type == "float32"){
                type = "float";
            }
            else if(type == "float64"){
                type = "real";
            }
            writer.writeAttribute("type", type);
            QString path = item.conVar.instancepath;
            if(path.endsWith('/')){
                path.chop(1);
            }
            writer.writeAttribute("path", path);
            writer.writeAttribute("scope", "outputs");
            writer.writeAttribute("subelement", item.conVar.subelement);
            writer.writeEndElement();
            break;
        }
    }
    writer.writeEndElement();

    writer.writeStartElement("message");
    writer.writeAttribute("id", "20003");
    writer.writeAttribute("name", "Emit");
    writer.writeAttribute("type", "enum {A661_FALSE, A661_TRUE}");
    writer.writeAttribute("tag", "A661_REQ_LAYER_INACTIVE");
    writer.writeAttribute("parameter", "A661_REQ_LAYER_INACTIVE");
    for(const MappingItem& item : sdys.outputItems){
        if(layer.pathFormRoot.value == item.eventVar.layerId && item.eventVar.widgetId == "-1"
            && item.eventVar.paramId == "A661_REQ_LAYER_INACTIVE" && item.eventVar.name == "Emit"){
            writer.writeStartElement("control_var");
            writer.writeAttribute("name", item.conVar.name);
            QString type = item.conVar.type;
            if(type == "int16"){
                type = "short";
            }
            else if(type == "uint16"){
                type = "ushort";
            }
            else if(type == "int32"){
                type = "int";
            }
            else if(type == "uint32"){
                type = "uint";
            }
            else if(type == "int64"){
                type = "int64";
            }
            else if(type == "uint64"){
                type = "uint64";
            }
            else if(type == "float32"){
                type = "float";
            }
            else if(type == "float64"){
                type = "real";
            }
            writer.writeAttribute("type", type);
            QString path = item.conVar.instancepath;
            if(path.endsWith('/')){
                path.chop(1);
            }
            writer.writeAttribute("path", path);
            writer.writeAttribute("scope", "outputs");
            writer.writeAttribute("subelement", item.conVar.subelement);
            writer.writeEndElement();
            break;
        }
    }
    writer.writeEndElement();

    writer.writeStartElement("message");
    writer.writeAttribute("id", "20004");
    writer.writeAttribute("name", "Emit");
    writer.writeAttribute("type", "enum {A661_FALSE, A661_TRUE}");
    writer.writeAttribute("tag", "A661_REQ_LAYER_VISIBLE");
    writer.writeAttribute("parameter", "A661_REQ_LAYER_VISIBLE");
    for(const MappingItem& item : sdys.outputItems){
        if(layer.pathFormRoot.value == item.eventVar.layerId && item.eventVar.widgetId == "-1"
            && item.eventVar.paramId == "A661_REQ_LAYER_VISIBLE" && item.eventVar.name == "Emit"){
            writer.writeStartElement("control_var");
            writer.writeAttribute("name", item.conVar.name);
            QString type = item.conVar.type;
            if(type == "int16"){
                type = "short";
            }
            else if(type == "uint16"){
                type = "ushort";
            }
            else if(type == "int32"){
                type = "int";
            }
            else if(type == "uint32"){
                type = "uint";
            }
            else if(type == "int64"){
                type = "int64";
            }
            else if(type == "uint64"){
                type = "uint64";
            }
            else if(type == "float32"){
                type = "float";
            }
            else if(type == "float64"){
                type = "real";
            }
            writer.writeAttribute("type", type);
            QString path = item.conVar.instancepath;
            if(path.endsWith('/')){
                path.chop(1);
            }
            writer.writeAttribute("path", path);
            writer.writeAttribute("scope", "outputs");
            writer.writeAttribute("subelement", item.conVar.subelement);
            writer.writeEndElement();
            break;
        }
    }
    writer.writeEndElement();


    writer.writeEndElement();

    /*========a661 layer children========*/

    writer.writeStartElement("children");

    printRdmfLayerWidgetChildren(writer, layer.pathFormRoot.value, layer.widgetChildren, symbology, 0, layer.width.toInt(), layer.height.toInt(), rules, eRules
                                 , propTypes, constMap, commuParams, sdys, 0, 0);

    //layer->children end
    writer.writeEndElement();

    //layer end
    writer.writeEndElement();
}

//LayerChildren
void writera661::printRdmfLayerChildren(QXmlStreamWriter &writer, const LayerChildren& layerChildren, const Symbology& symbology
                                        , const Rules rules, const ExtensionRules eRules, const PropTypes &propTypes
                                        , const QMap<QString, QString> &constMap, const CommuParams &commuParams, const SdyContent &sdys)
{
    QList<Layer> layers = layerChildren.layers;

    /*========a661 layers========*/
    for(int i = 0; i < layers.count(); i++)
    {
        Layer layer = layers.at(i);
        printRdmfLayer(writer, layer, symbology, rules, eRules, propTypes, constMap, commuParams, sdys);
    }
}

//spicification
void writera661::printRdmfSpecification(QXmlStreamWriter &writer, const QString &rdmfPath, const Specification& specification
                                        , const Rules rules, const ExtensionRules eRules, const PropTypes &propTypes
                                        , const QMap<QString, QString> &constMap, const CommuParams &commuParams, const SdyContent &sdys)
{
    /*========== 1 specification===========*/
    writer.writeStartElement("specification");
    writer.writeAttribute("oid", specification.oid);

    /*========== 2 IDE===========*/

    printRdmfIDE(writer, rdmfPath,specification.ide);

    /*========== 2 symbology===========*/

    printRdmfSymbology(writer, specification.Symbology);

    /*========== 2 A661===========*/

    printRdmfA661(writer, specification.a661);

    /*========== 2 children===========*/

    writer.writeStartElement("children");


    //打印每层
    printRdmfLayerChildren(writer, specification.layerChildren, specification.Symbology, rules, eRules, propTypes, constMap, commuParams, sdys);

    //specification->children
    writer.writeEndElement();

    //specification
    writer.writeEndElement();
}


void writera661::genRdmfFile(QString genRdmfPath, SGFX &sgfx, const Rules rules, const ExtensionRules eRules, const PropTypes &propTypes
                             , const QMap<QString, QString> &constMap, const CommuParams &commuParams, const SdyContent &sdys)
{
    QFileInfo etpInfo(genRdmfPath);

    // 如果目录不存在，则尝试创建目录
    QDir dir = etpInfo.dir();
    if (!dir.exists()) {
        if (!dir.mkpath(".")) {
            qDebug() << "无法创建目录：" << dir.absolutePath();
            return;
        }
    }

    QFile file(genRdmfPath);
    // 尝试以写入模式打开文件
    if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
    {
        QXmlStreamWriter writer(&file);
        writer.setAutoFormatting(true);

        /*=======xml dom scade_release=========*/
        writer.writeStartDocument("1.0");
        // 写入自定义处理指令
        writer.writeProcessingInstruction("dom", "version=\"19.0\"");
        writer.writeProcessingInstruction("scade_release", "version=\"1.0\"");

        /*/=================正文======================/*/
        printRdmfSpecification(writer, genRdmfPath, sgfx.specification, rules, eRules, propTypes, constMap, commuParams, sdys);

        file.close(); // 完成写入后关闭文件
    }

}

bool writera661::copyFilesByExtension(const QString& sourceFolderPath, const QString& targetFolderPath, const QStringList& extensions)
{
    QDir sourceDir(sourceFolderPath);
    if (!sourceDir.exists()) {
        qDebug() << "源文件夹不存在：" << sourceFolderPath;
        return false;
    }

    // 创建目标目录（如果不存在）
    QDir targetDir(targetFolderPath);
    if (!targetDir.exists() && !targetDir.mkpath(".")) {
        qDebug() << "无法创建目标目录：" << targetFolderPath;
        return false;
    }

    bool success = true;
    // 遍历源文件夹中的所有文件
    QFileInfoList fileList = sourceDir.entryInfoList(QDir::Files);
    for (const QFileInfo& fileInfo : fileList) {
        // 检查文件扩展名是否在指定列表中
        if (extensions.contains(fileInfo.suffix().toLower())) {
            QString targetFilePath = targetDir.filePath(fileInfo.fileName());

            // 如果目标文件已存在，先删除
            if (QFile::exists(targetFilePath)) {
                QFile::remove(targetFilePath);
            }

            // 执行复制
            if (!QFile::copy(fileInfo.absoluteFilePath(), targetFilePath)) {
                qDebug() << "复制失败：" << fileInfo.fileName();
                success = false;
            } else {
                qDebug() << "复制成功：" << fileInfo.fileName();
            }
        }
    }

    return success;
}

void writera661::genResourceFile(QString genResourcePath, QString folderPath)
{
    QStringList extensions = {"sct", "sft", "sst", "swt", "cnt", "pdt", "sdt", "slc", "sld", "sdfx"};

    copyFilesByExtension(folderPath, genResourcePath, extensions);

}

bool writera661::copyDirectory(const QString &srcPath, const QString &dstPath) {
    QDir srcDir(srcPath);
    if (!srcDir.exists()) {
        return false;
    }

    QDir dstDir(dstPath);
    if (!dstDir.exists() && !dstDir.mkpath(".")) {
        return false;
    }

    foreach (const QFileInfo &info, srcDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs)) {
        QString srcItem = info.filePath();
        QString dstItem = dstPath + QDir::separator() + info.fileName();

        if (info.isDir()) {
            if (!copyDirectory(srcItem, dstItem)) {
                return false;
            }
        } else if (info.isFile()) {
            if (QFile::exists(dstItem)) {
                QFile::remove(dstItem);
            }
            if (!QFile::copy(srcItem, dstItem)) {
                return false;
            }
        }
    }
    return true;
}

bool writera661::copyProjectFolder(const QString &etpPathAbs, const QString &genResourcePath) {

    // 复制picture文件夹
    QString pictureSrc = etpPathAbs + "/picture";
    QString pictureDst = genResourcePath + "picture";
    if (!copyDirectory(pictureSrc, pictureDst)) {
        return false;
    }

    // 复制fonts文件夹
    QString fontsSrc = etpPathAbs + "/fonts";
    QString fontsDst = genResourcePath + "fonts";
    if (!copyDirectory(fontsSrc, fontsDst)) {
        return false;
    }

    return true;
}
